import { toLatLng } from "../geometry/LatLng";
import { toPoint } from "../geometry/Point";
import utils from "../../utils";
import { svgFloow, svgBias, svgWall } from "../../svg";
import { toCoorsOffset, coorsOffset } from "../util/CoorsOffset";

import CoorsOffset from "../util/CoorsOffset";

// import { drawImage, drawPoint } from "../drawing/drawing";
import * as Draw from "../drawing/drawing";
import {
  getGaoDeTileUrl,
  getWMSUrl,
  WMSXYZ,
  getArcgisUrl,
  XYZ,
} from "../layer/TileLayer";

export class Projection {
  crspro;
  crs;
  // 缩放级别
  zoom;
  // 中心点
  centerPoint;
  // 地球半径
  EARTH_RAD = 6378137;
  // 地球周长
  EARTH_PERIMETER = 2 * Math.PI * this.EARTH_RAD;
  // 瓦片像素
  TILE_SIZE = 256;
  baseLayerCache = [];
  office = toPoint(0, 0);
  baseLayer = [];
  drawLayer = [];
  measureLayer = [];
  checkInfos = [];
  animate = false; // 动画
  lng;
  lat;
  render;

  currMousePoint = toPoint(0, 0);
  currMouseLngLat = toLatLng(0, 0);
  WMSstop = true; // 用来设置WMS什么时候开始刷新（移动过程中WMS不刷新,WMST要刷新）
  centerMercator = toPoint(0, 0);

  constructor({
    lng,
    lat,
    zoom,
    ctx,
    canvas,
    baseLayer,
    drawLayer,
    measureLayer,
    animate,
    crs,
    crspro,
  }) {
    this.lng = lng;
    this.lat = lat;
    this.canvas = canvas;
    this.ctx = ctx;
    this.zoom = zoom;
    this.crs = crs;
    this.crspro = crspro;
    this.baseLayer = baseLayer;
    this.initBaseLayerCache();
    this.drawLayer = drawLayer;
    this.measureLayer = measureLayer;
    this.centerPoint = toPoint(lng, lat);
    this.width = this.canvas.width;
    this.height = this.canvas.height;
    this.ctx.clearRect(0, 0, this.width, this.height);
    this.updata(this.lng, this.lat);
    this.centerMercator = this.crspro.lngLatToPoint(toLatLng(lng, lat), zoom);
    this.animate = animate;
    if (animate) {
      this.start();
    }
    this.loadBgCanvas();
  }

  initBaseLayerCache() {
    this.baseLayerCache = this.baseLayer.map((item) => {
      if (item.type === "geojson") {
        // if (item.crs && item.crs === "EPSG4326") {
        //   let info = item.data;

        //   let nk = info.features[0].geometry.coordinates[0][0];
        //   const nk2 = nk.map((e) => {
        //     const temp = toCoorsOffset().gcj02towgs84(e[0], e[1]);
        //     return [temp.lng, temp.lat];
        //   });
        //   // nk =[]
        //   info.features[0].geometry.coordinates[0][0] = nk2;

        //   return { type: item.type, data: [info] };
        // } else {
        //   return { type: item.type, data: [item.data] };
        // }

        return { type: item.type, data: [item.data] };
      } else {
        return { type: item.type, data: [] };
      }
    });
  }

  scaleMap({ lng, lat, zoom }) {
    const lnglat = toLatLng(lng, lat);
    this.centerMercator = this.crspro.lngLatToPoint(lnglat, zoom);
    this.zoom = zoom;
    this.initBaseLayerCache();
    this.office = toPoint(0, 0);
    this.updata(lng, lat);
  }
  WMSstopFn(bool) {
    this.WMSstop = bool;
  }

  updata(lng, lat) {
    const clnglat = toLatLng(lng, lat);

    // this.updataWMS(lng, lat);
    //

    const { zoom } = this;

    // 求出中心点墨卡托投影坐标
    const centerPos = this.crspro.lngLatToPoint(clnglat, zoom).floor();
    // 求出中心点瓦片坐标
    this.centerTile = centerPos.divideBy(256).floor();
    // 根据中心点瓦片坐标求出该瓦片左上角墨卡托投影坐标
    let centerTilePos = this.getPxFromTile(this.centerTile);
    // 求出偏移
    const offset = centerPos.subtract(centerTilePos);

    const tiles = this.getRange(this.centerTile, offset, this.office);
    tiles.forEach((itemFirst, indexFisrt) => {
      itemFirst.forEach((item, index) => {
        // 因为该方法鼠标移动一个像素就会执行一次，所以这个数组会获取比较多的次数，
        // 通过isf，判断一下总数组里边是否有这个数组了，
        // 没有才去绘制图片，才在imgs里增加子集
        const isf = this.baseLayerCache[indexFisrt].data.some(
          (it) => it.x === item.x && it.y === item.y && it.z === item.z
        );
        if (!isf && this.baseLayerCache[indexFisrt].type !== "geojson") {
          this.baseLayerCache[indexFisrt].data.push(item);
        }
      });
    });

    // 给瓦片排个序，从中间到四周去加载，当然，因为是哪个图片一加载出来就显示，这一步虽然有用但几乎可以省略
    this.baseLayerCache.forEach((item) => {
      if (item.type === "WMTS" || item.type === "WMSXYZ") {
        item.data.sort((a, b) => {
          const tempa = toPoint(a.x, a.y);
          const tempb = toPoint(b.x, b.y);
          return (
            tempa.distanceTo(this.centerTile) -
            tempb.distanceTo(this.centerTile)
          );
        });
      }
    });
  }

  layerPointToLatLng(point) {
    //投影点
    const projectedPoint = toPoint(point).add(this.getPixelOrigin());
    return this.unproject(projectedPoint, this._zoom);
  }

  loadBgCanvas() {
    utils
      .svgSetColor({ source: svgBias, color: "#18C65F", cw: 40, ch: 40 })
      .then((res) => {
        this.img = res;
      });

    utils.svgSetColor({ source: svgFloow, color: "#559CC4" }).then((res) => {
      this.img2 = res;
    });

    utils.svgSetColor({ source: svgWall, color: "#D768BC" }).then((res) => {
      this.img3 = res;
    });
  }
  // 根据中心点的经纬度求出在画布上偏移xy之后得到的坐标
  lnglatMoveXY(lng, lat, x = 0, y = 0) {
    const { zoom } = this;
    const mer = this.crspro.projection.project(toLatLng(lng, lat));
    const centerToMercator = toPoint(mer.x, mer.y);
    // 当前层级分辨率
    let resolution = this.getResolution(zoom);
    const moveCenterToMercator = centerToMercator.subtract(
      toPoint(x * resolution, y * resolution)
    );
    return this.crspro.projection.unproject(moveCenterToMercator);
  }

  updataWMS(lng, lat) {
    // const lnglatLeftTop = this.lnglatMoveXY(lng, lat, 250, -250);
    // const lnglatRightBottom = this.lnglatMoveXY(lng, lat, -250, 250);

    const clnglat = toLatLng(lng, lat);
    const centerPos2 = this.crspro.lngLatToPoint(clnglat, this.zoom).floor();
    const bb = centerPos2.subtract(toPoint(250, -250));
    const bb1 = centerPos2.subtract(toPoint(-250, 250));

    //  const lnglatLeftTop = this.lnglatMoveXY(lng, lat, 250, -250);
    //  const lnglatRightBottom = this.lnglatMoveXY(lng, lat, -250, 250);

    const lnglatLeftTop = this.crspro.pointToLatLng(bb, this.zoom);
    const lnglatRightBottom = this.crspro.pointToLatLng(bb1, this.zoom);

    const mk = [];
    mk.push(lnglatLeftTop.lng);
    mk.push(lnglatLeftTop.lat);
    mk.push(lnglatRightBottom.lng);
    mk.push(lnglatRightBottom.lat);

    // const aa = getWMSUrl({
    //   // url: "http://localhost:6080/arcgis/rest/services/newhaha/haha/MapServer",
    //   // url: "http://localhost:6080/arcgis/rest/services/SampleWorldCities/MapServer",
    //   url: "http://192.168.0.25:6163/igs/rest/mrms/docs/ZCQCHXZQ",
    //   parameters: {
    //     dpi: 96,
    //     transparent: true,
    //     format: "png8",
    //     imageSR: 4490,
    //     f: "image",
    //     bboxSR: 4490,
    //     bbox: mk.toString(),
    //     size: `${this.canvas.width},${this.canvas.height}`,
    //   },
    // });

    const aa = WMSXYZ("http://192.168.0.25:6163/igs/rest/mrms/docs/ZCQCHXZQ", {
      bbox: mk.toString(),
    });
    this.baseLayerCache.forEach((item, index) => {
      if (item.type === "WMS") {
        const image = new Image();
        image.src = aa;
        item.data = [
          {
            image,
          },
        ];
      }
    });
  }
  moveTo(offi) {
    this.office = offi;
  }
  mouseMove(point, lnglat) {
    this.currMousePoint = point;
    this.currMouseLngLat = lnglat;
  }

  /**
   * 获取地图应该显示的范围编号
   * @param {*} centerTile  中心点瓦片坐标
   * @param {*} offset 偏移量
   * @returns
   */
  getRange(centerTile, offset) {
    // 计算瓦片数量
    let rowMinNum = Math.ceil((this.width / 2 - offset.x) / this.TILE_SIZE); // 左
    let colMinNum = Math.ceil((this.height / 2 - offset.y) / this.TILE_SIZE); // 上
    let rowMaxNum = Math.ceil(
      (this.width / 2 - (this.TILE_SIZE - offset.x)) / this.TILE_SIZE
    ); // 右
    let colMaxNum = Math.ceil(
      (this.height / 2 - (this.TILE_SIZE - offset.y)) / this.TILE_SIZE
    ); // 下

    // console.log(rowMinNum, colMinNum, rowMaxNum, colMaxNum);
    // 从上到下，从左到右，加载瓦片
    return this.baseLayer.map((element) => {
      const { type } = element;
      if (type === "WMS") {
        return [];
      } else {
        const tiles = [];
        for (let i = -rowMinNum; i <= rowMaxNum; i++) {
          for (let j = -colMinNum; j <= colMaxNum; j++) {
            // if (
            //   centerTile.x + i < Math.pow(this.zoom, 2) &&
            //   centerTile.y + j < Math.pow(this.zoom, 2)
            // ) {
            const image = new Image();
            if (type === "WMTS") {
              image.src = XYZ(
                element.url,
                centerTile.x + i,
                centerTile.y + j,
                this.zoom
              );
            } else if (type === "WMSXYZ") {
              const bbox = this.crspro.bbox(
                centerTile.x + i,
                centerTile.y + j,
                this.zoom
              );
              image.src = WMSXYZ(element.url, {
                bbox,
              });
            }

            const obj = {
              image,
              x: centerTile.x + i,
              y: centerTile.y + j,
              n: i * this.TILE_SIZE - offset.x - this.office.x + this.width / 2,
              k:
                j * this.TILE_SIZE - offset.y - this.office.y + this.height / 2,
              z: this.zoom,
            };

            tiles.push(obj);
            // }
          }
        }
        return tiles;
      }
    });
  }

  setImageUrl(sources) {
    const { image, x, y, z } = sources;
    image.src = getGaoDeTileUrl(x, y, z);
  }

  /**
   * 加载图片的回调函数
   * @param {*} sources
   * @param {*} callback
   */
  loadedImg(sources, callback) {
    const { image, x, y, z } = sources;

    image.src = getGaoDeTileUrl(x, y, z);
    image.src = getArcgisUrl(x, y, z);
    image.onload = () => {
      callback(sources);
    };
  }
  loadedImgThen(sources) {
    var promise = new Promise(function (resolve, reject) {
      const { image, x, y, z } = sources;
      image.src = getGaoDeTileUrl(x, y, z);
      image.onload = () => {
        resolve(sources);
      };
      image.onerror = (err) => {
        reject(err);
      };
    });
    return promise;
  }

  /**
   * 获取某一层级下的分辨率
   * @param {*} n
   * @returns
   */
  getResolution = (n) => {
    const tileNums = Math.pow(2, n);
    const tileTotalPx = tileNums * this.TILE_SIZE;
    return this.EARTH_PERIMETER / tileTotalPx;
  };

  /**
   * 根据经度纬度层级算出行列
   *  已废弃
   * @param {*} olng
   * @param {*} olat
   * @param {*} zoom
   * @returns
   */
  getTileRowAndCol = (lnglat, zoom) => {
    let { x, y } = this.crspro.projection.project(lnglat);
    x += this.EARTH_PERIMETER / 2; // ++
    y = this.EARTH_PERIMETER / 2 - y; // ++
    let resolution = this.getResolution(zoom);
    let row = Math.floor(x / resolution / this.TILE_SIZE);
    let col = Math.floor(y / resolution / this.TILE_SIZE);
    return toPoint(row, col);
  };
  // 根据经纬度算出投影 已废弃
  getPxFromLngLat = (lnglat, z) => {
    const mer = this.crspro.projection.project(lnglat);
    let _x = mer.x;
    let _y = mer.y;
    // 转成世界平面图的坐标
    _x += this.EARTH_PERIMETER / 2;
    _y = this.EARTH_PERIMETER / 2 - _y;
    let resolution = this.getResolution(z); // 该层级的分辨率

    // 米/分辨率得到像素
    let x = Math.floor(_x / resolution);
    let y = Math.floor(_y / resolution);
    return toPoint(x, y);
  };

  // 经纬度转图层上的点,注意，转出来的是坐标原点到此处的位置
  latLngToLayerPoint(lnglat) {
    const point = this.crspro.lngLatToPoint(lnglat, this.zoom);
    const temp = point
      .subtract(this.centerMercator)
      .add(toPoint(this.width / 2, this.height / 2));

    return temp;
  }

  drawPointhandle({
    coordinate,
    color = "#ff4f02",
    radius = 10,
    borderWidth = 0,
    borderColor = "#000",
  }) {
    const pos = this.latLngToLayerPoint(toLatLng(coordinate[0], coordinate[1]));
    Draw.drawPoint({
      ctx: this.ctx,
      x: pos.x + this.office.x,
      y: pos.y + this.office.y,
      borderWidth,
      borderColor,
      color,
      radius,
    });
  }
  drawTexthandle({
    coordinate,
    color = "#ff4f02",
    radius = 10,
    text,
    marginTop,
  }) {
    const pos = this.latLngToLayerPoint(toLatLng(coordinate[0], coordinate[1]));
    Draw.drawText({
      ctx: this.ctx,
      x: pos.x + this.office.x,
      y: pos.y + this.office.y,
      text,
      strokeWidth: 5,
      color,
      marginTop,
    });
  }

  drawPolygonhandle({
    coordinates,
    type = "polygon", // pylygon pylyline geo
    borderColor = "#000",
    borderWidth = 1,
    setLineDash = [0], // 可传入指譬如[3, 5]
    barckgroudColor = "#ccc",
    barckgroudColorHover = "",
    cursor = "pointer",
  }) {
    const tempCoordinates = coordinates.map((item) => {
      const pos = this.latLngToLayerPoint(toLatLng(item[0], item[1]));
      return [pos.x + this.office.x, pos.y + this.office.y];
    });

    Draw.drawPolygon({
      ctx: this.ctx,
      type,
      coordinates: tempCoordinates,
      borderColor,
      borderWidth,
      setLineDash,
      barckgroudColor,
      barckgroudColorHover,
      cursor,
    });
  }

  /**
   * 根据瓦片坐标获取该瓦片左上角的x,y
   * @param {*} loc
   * @returns
   */
  getPxFromTile(loc) {
    const { x, y } = loc;
    return toPoint(x * this.TILE_SIZE, y * this.TILE_SIZE);
  }
  renderDraw() {
    // 清空画布
    this.ctx.clearRect(0, 0, this.width, this.height);

    // 先画底图
    this.baseLayerCache.forEach((element, index) => {
      element.data.forEach((e) => {
        if (element.type === "WMTS" || element.type === "WMSXYZ") {
         Draw.drawImage({
            ctx: this.ctx,
            image: e.image,
            x: e.n + this.office.x,
            y: e.k + this.office.y,
            w: this.TILE_SIZE,
            h: this.TILE_SIZE,
          });
        } else if (element.type === "WMS") {
          Draw.drawImage({
            ctx: this.ctx,
            image: e.image,
            x: 0 + this.office.x,
            y: 0 + this.office.y,
            w: this.canvas.width,
            h: this.canvas.height,
          });
        } else if (element.type === "geojson") {
          Draw.drawGeoJson({ ctx: this.ctx, data: e, projection: this });
        }
      });
    });

    this.checkInfos = [];
    // 再画其它图层
    this.drawLayer.forEach((item) => {
      if (item.type === "point") {
        let coordinate = item.coordinate;
        if (item.sys && item.sys === "GCJ02") {
          const temp = coorsOffset().gcj02towgs84(coordinate[0], coordinate[1]);
          coordinate = [temp.lng, temp.lat];
        }
        this.drawPointhandle({ coordinate });
        this.drawTexthandle({
          coordinate,
          text: item.text,
          marginTop: 25,
        });
      } else if (item.type === "polygon") {
        const coordinates = item.coordinates;
        this.drawPolygonhandle({
          coordinates,
        });
      }
      if (
        this.ctx.isPointInPath(this.currMousePoint.x, this.currMousePoint.y)
      ) {
        // 把最后添加的图层加到点击时候的第一层
        this.checkInfos.unshift(item);
      }
    });

    this.measureLayer.forEach((item) => {
      const coordinates = item.coordinates;
      this.drawPolygonhandle({
        borderColor: item.type === "polyline" ? "#F3FF82" : "#033460",
        type: item.type,
        borderWidth:item.type === "polyline" ? 3 : 0.1,
        barckgroudColor: "#2497FF80",
        coordinates,
      });
      if (item.type === 'polyline') {
        coordinates.forEach((it, index, count) => {
          if (index < count.length - 1) {
            this.drawPointhandle({
              coordinate: it,
              color: "#F99700",
              radius: 3,
              borderWidth: 5,
              borderColor: "#E2F900",
            });
            let aa = "";
            if (index > 0) {
              // const aa = this.crspro.distanceTo(it, count[index - 1]);
              aa = this.crspro.distance(
                toLatLng(it[0], it[1]),
                toLatLng(count[index - 1][0], count[index - 1][1]),
                true
              );
            }
            this.drawTexthandle({
              coordinate: it,
              text: index === 0 ? "起点" : aa,
              color: "#000",
              marginTop: 18,
            });
          } else {
            if (item?.id) {
              this.drawPointhandle({
                coordinate: it,
                color: "#F99700",
                radius: 3,
                borderWidth: 5,
                borderColor: "#E2F900",
              });
              this.drawTexthandle({
                coordinate: it,
                text: "总长：100千米",
                color: "#000",
                marginTop: 18,
              });
            }
          }
        });
      } else { 
          coordinates.forEach((it, index, count) => {
            this.drawPointhandle({
              coordinate: it,
              color: "#FDFF00",
              radius: 3,
              borderWidth: 5,
              borderColor: "#0C8BFF",
            });
          });
        
        if (item?.id) {
           
           const {cenLng, cenLat } = this.crspro.areaCenter(coordinates);
           this.drawTexthandle({
             coordinate: [cenLng, cenLat],
             text: this.crspro.computeSignedArea(coordinates),
             color: "#000",
             marginTop: 18,
           });


          //  const obj = [
          //    { lat: 27.047944995715422, lng: 102.73129657902908 },
          //    { lat: 25.047944995715422, lng: 103.73129657902908 },
          //    { lat: 26.047944995715422, lng: 102.73129657902908 },
     
          //  ];
      
         }
      }
    });

    Draw.drawText({
      ctx: this.ctx,
      x: this.canvas.width - 350,
      y: this.canvas.height - 10,
      textAlign: "left",
      text: `经度：${this.currMouseLngLat.lng} ，纬度：${this.currMouseLngLat.lat}`,
    });

    // 再画其它图层
    // this.drawLayer.forEach((item) => {
    //   if (item.type === "point") {
    //     this.drawPointhandle({ coordinate: item.coordinate });
    //     this.drawTexthandle({
    //       coordinate: item.coordinate,
    //       text: item.text,
    //       marginTop: 25,
    //     });
    //   } else if (item.type === "polygon") {
    //     this.drawPolygonhandle({
    //       coordinates: item.coordinates,
    //     });
    //   }
    // });
  }
  start() {
    // console.log("我一直在循环");
    // this.updata(this.lng, this.lat);
    this.renderDraw();
    this.render = requestAnimationFrame(this.start.bind(this));

    // if (this.animation) {
    //   let isf = false;
    //   this.animation.forEach((item) => {
    //     if (item.key === "mapCenterPosX") {
    //       this.mapCenterPos = [
    //         (this.mapCenterPos[0] += item.dur),
    //         this.mapCenterPos[1],
    //       ];
    //       if (this.mapCenterPos[0] > item.future) {
    //         isf = true;
    //       }
    //     } else if (item.key === "mapCenterPosY") {
    //       this.mapCenterPos = [
    //         this.mapCenterPos[0],
    //         (this.mapCenterPos[1] += item.dur),
    //       ];
    //     } else if (item.key === "scale") {
    //       this.scale = this.scale += item.dur;
    //     }
    //   });

    //   if (isf) {
    //     this.animation = null;
    //   }
    // }
  }
  destroy() {
    cancelAnimationFrame(this.render);
  }
}
